package com.tl.boot.common.wrapper;

import com.alibaba.fastjson.JSONObject;
import com.tl.boot.common.constants.RequestConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.util.*;

/**
 * com.tl.boot.common.wrapper -- DecorateHttpServletRequestWrapper
 * Description:
 * Created by joshua_liu <a href="mailto:joshualwork@163.com"></a>
 * On 2019/9/11 8:43
 */
public class DecorateHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private static final Logger log = LoggerFactory.getLogger(DecorateHttpServletRequestWrapper.class);
    /**
     * 请求方法为post时的请求体
     */
    private byte[] body;
    private Map<String, String[]> parameterMap;
    /**
     * 请求方法为get时的请求参数
     */
    private String queryString;

    public DecorateHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);

        try {
            body = getByteByStream(request.getInputStream());
            Map<String, String[]> tmp = request.getParameterMap();

            if (tmp != null && tmp.size() > 0) {
                parameterMap = new HashMap<>(tmp.size());

                for (Map.Entry<String, String[]> entry : tmp.entrySet()) {
                    parameterMap.put(entry.getKey(), entry.getValue());
                }

                refreshQueryString();
            }
        } catch (Exception e) {
            log.error("", e);
        }
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream stream = new ByteArrayInputStream(body);

        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {
            }

            @Override
            public int read() throws IOException {
                return stream.read();
            }
        };
    }

    @Override
    public Enumeration<String> getParameterNames() {
        Vector<String> vector = new Vector<>(parameterMap.keySet());
        return vector.elements();
    }

    @Override
    public String getParameter(String name) {
        String[] results = null;
        if (parameterMap != null) {
            results = parameterMap.get(name);
        }
        if (results == null || results.length <= 0) {
            return null;
        } else {
            return results[0];
        }
    }

    @Override
    public String[] getParameterValues(String name) {
        String[] results = parameterMap.get(name);

        if (results == null || results.length <= 0) {
            return null;
        } else {
            return results;
        }
    }

    public String getParams() {
        switch (this.getMethod()) {
            case RequestConstant.REQUEST_METHOD_GET:
                return this.queryString;
            case RequestConstant.REQUEST_METHOD_POST:
                return getBody();
            default:
                return null;
        }
    }

    public JSONObject getHeaders() {
        JSONObject result = new JSONObject();
        Enumeration<String> headerNames = this.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            result.put(headerName, this.getHeader(headerName));
        }
        log.info("request>>>heades>>>{}", result);
        return result;
    }

    public String getBody() {
        if (body == null) {
            return null;
        }
        try {
            return new String(body, "utf-8");
        } catch (UnsupportedEncodingException e) {
            log.error("", e);
            return null;
        }
    }

    public void modifyBody(byte[] body) {
        this.body = body;
    }

    public void addParameterValue(String name, String value) {
        if (parameterMap == null) {
            parameterMap = new HashMap<>(16);
        }

        String[] values = parameterMap.get(name);

        if (values != null && values.length > 0) {
            values[0] = value;
            parameterMap.put(name, values);
        } else {
            values = new String[]{value};
            parameterMap.put(name, values);
        }

        refreshQueryString();
    }

    private byte[] getByteByStream(InputStream is) throws Exception {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        while ((len = is.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }

        bos.flush();
        return bos.toByteArray();
    }

    private void refreshQueryString() {
        if (parameterMap == null) {
            queryString = null;
        }

        List<String> tmp = new ArrayList<>();

        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            for (String value : entry.getValue()) {
                tmp.add(String.format("%s=%s", entry.getKey(), value));
            }
        }

        queryString = String.join("&", tmp);
    }

    public String getIP() {
        return "";
    }
}
